//
//  File.swift
//  LocationTrackerAdmin
//
//  Created by mac on 2025/4/5.
//

import Foundation
import Vapor
import FluentKit
struct OpenIMResponse<T: Content>: Content {
    let errCode: Int
    let errMsg: String
    let errDlt: String
    let data: T?
}

struct OpenIMToken: Content {
    let token: String
    let expireTimeSeconds: Int
}

struct IMManager {
    let application: Application

    private var openIMServer = Environment.get("OpenIM_Server_API") ?? ""
    
    var accessToken: String = ""
    
    init(application: Application) {
        self.application = application
    }
    
    mutating func getAccessToken() async throws {
        struct RegistUserModel: Content {
            let secret: String
            let userID: String
        }
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/auth/get_admin_token"), headers: ["operationID": "\(Date().timeIntervalSince1970)"], content: RegistUserModel(secret: "openIM123", userID: "imAdmin"))
        let response = try res.content.decode(OpenIMResponse<OpenIMToken>.self)
        if response.data != nil {
            self.accessToken = response.data!.token
        }
    }
    
    //注册用户
    func registUser(userID: String) async throws -> OpenIMToken? {
        struct RegistUserModel: Content {
            let users: [UserProfile]
            struct UserProfile: Content {
                let userID: String
                let nickname: String
                let faceURL: String
            }
        }
        let user = try await UserModel.query(on: application.db)
            .filter(\.$id == userID)
            .first()
        let userParam = RegistUserModel(users: [RegistUserModel.UserProfile(userID: userID, nickname: user?.name ?? "", faceURL: user?.avatar ?? "")])
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/user/user_register"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: userParam)
        let _ = try res.content.decode(OpenIMResponse<String>.self)
        struct GetTokenParam: Content {
            let platformID: Int
            let userID: String
        }
        let userRes = try await self.application.client.post(URI(string: self.openIMServer + "/auth/get_user_token"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: GetTokenParam(platformID: 1, userID: userID))
        let userResponse = try userRes.content.decode(OpenIMResponse<OpenIMToken>.self)
        if userResponse.data != nil {
            return userResponse.data!
        }
        return nil
    }
    
    //创建群组
    func createGroup(adminID: String, groupID: String) async throws -> Bool {
        struct CreateGroupParam: Content {
            let memberUserIDs: [String]
            let adminUserIDs: [String]
            let ownerUserID: String
            let groupInfo: GroupInfo
            struct GroupInfo: Content {
                let groupID: String
                let groupName: String
                let notification: String
                let introduction: String
                let faceURL: String
                let ex: String
                let groupType: Int
                let needVerification: Int
                let lookMemberInfo: Int
                let applyMemberFriend: Int
            }
        }
        let group = CreateGroupParam(memberUserIDs: [], adminUserIDs: [], ownerUserID: adminID, groupInfo: CreateGroupParam.GroupInfo(groupID: groupID, groupName: "定位分享群", notification: "notification", introduction: "定位分享群", faceURL: "", ex: "ex", groupType: 2, needVerification: 0, lookMemberInfo: 0, applyMemberFriend: 0))
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/group/create_group"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: group)
        struct CreateGroupResponseData: Content {
            let groupInfo: GroupInfo
            struct GroupInfo: Content {
                let groupID: String
                let groupName: String
                let notification: String
                let introduction: String
                let faceURL: String
                let ownerUserID: String
                let createTime: Int
                let memberCount: Int
                let ex: String
                let status: Int
                let creatorUserID: String
                let groupType: Int
                let needVerification: Int
                let lookMemberInfo: Int
                let applyMemberFriend: Int
                let notificationUpdateTime: Int
                let notificationUserID: String
            }
        }
        let response = try res.content.decode(OpenIMResponse<CreateGroupResponseData>.self)
        if response.errCode == 0 {
            return true
        }
        return false
    }
    
    //加入群组
    func joinGroup(groupId: String, userID: String) async throws -> Bool {
        struct JoinGroupParam: Content {
            let groupID: String
            let reqMessage: String
            let joinSource: Int
            let inviterUserID: String
        }
        let joinRequest = JoinGroupParam(groupID: groupId, reqMessage: "", joinSource: 1, inviterUserID: userID)
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/group/join_group"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: joinRequest)
        let response = try res.content.decode(OpenIMResponse<Bool>.self)
        if response.errCode == 0 {
            struct AgreeJoinGroupParam: Content {
                let groupID: String
                let fromUserID: String
                let handledMsg: String
                let handleResult: Int
            }
            let agreeData = AgreeJoinGroupParam(groupID: groupId, fromUserID: userID, handledMsg: "", handleResult: 1)
            let agreeRes = try await self.application.client.post(URI(string: self.openIMServer + "/group/group_application_response"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: agreeData)
            let agreeResponse = try agreeRes.content.decode(OpenIMResponse<Bool>.self)
            if agreeResponse.errCode == 0 {
                return true
            } else {
                return false
            }
        }
        return false
    }
    
    //退出群组
    func quitGroup(groupId: String, userID: String) async throws -> Bool {
        struct QuitGroupParam: Content {
            let groupID: String
            let userID: String
        }
        let quitRequest = QuitGroupParam(groupID: groupId, userID: userID)
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/group/quit_group"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: quitRequest)
        let response = try res.content.decode(OpenIMResponse<Bool>.self)
        if response.errCode == 0 {
            return true
        }
        return false
    }
    
    //移除群成员
    func deleteGroupMember(groupId: String, userID: String) async throws -> Bool {
        struct DeleteGroupMemberParam: Content {
            let groupID: String
            let kickedUserIDs: [String]
            let reason: String
        }
        let quitRequest = DeleteGroupMemberParam(groupID: groupId, kickedUserIDs: [userID], reason: "admin kick")
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/group/kick_group"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: quitRequest)
        let response = try res.content.decode(OpenIMResponse<Bool>.self)
        if response.errCode == 0 {
            return true
        }
        return false
    }
    
    //删除群组
    func deleteGroup(groupId: String) async throws -> Bool {
        struct DeleteGroupParam: Content {
            let groupID: String
        }
        let quitRequest = DeleteGroupParam(groupID: groupId)
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/group/dismiss_group"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: quitRequest)
        let response = try res.content.decode(OpenIMResponse<Bool>.self)
        if response.errCode == 0 {
            return true
        }
        return false
    }
    
    //发送一条消息
    func sendLocationMessage(from: String, to userID: String, location: LocationInfoParam) async throws -> Bool {
        struct SendMessageParam: Content {
            let sendID: String
            let recvID: String?
            let groupID: String?
            struct MessageContent: Content {
                let data: String
                let description: String?
            }
            let content: MessageContent
            let contentType: Int
            let sessionType: Int
            let isOnlineOnly: Bool
        }
        let locationData = try JSONEncoder().encode(location)
        let locationStr = String(data: locationData, encoding: .utf8) ?? ""
        let data = SendMessageParam(sendID: from, recvID: userID, groupID: nil, content: SendMessageParam.MessageContent(data: locationStr, description: nil), contentType: 110, sessionType: 1, isOnlineOnly: true)
        let res = try await self.application.client.post(URI(string: self.openIMServer + "/msg/send_msg"), headers: ["operationID": "\(Date().timeIntervalSince1970)", "token": self.accessToken], content: data)
        struct SendMessageResponseData: Content {
            let serverMsgID: String
            let clientMsgID: String
            let sendTime: TimeInterval
        }
        let response = try res.content.decode(OpenIMResponse<SendMessageResponseData>.self)
        print(response)
        if response.errCode == 0 {
            return true
        }
        return false
    }
}

extension Application {
    struct IMManagerKey: StorageKey {
        typealias Value = IMManager
    }
    
    var imClient: IMManager {
        get { storage[IMManagerKey.self]! }
        set { storage[IMManagerKey.self] = newValue }
    }
}
